#define F_CPU 1.0e6  // 1 MHz

/****************************************************************************

   _                         _                    
  (_)_ __  _ __ ___  ___ ___(_)_   _____ _ __ ___ 
  | | '__|| '__/ _ \/ __/ _ \ \ \ / / _ \ '__/ __|
  | | |   | | |  __/ (_|  __/ |\ V /  __/ | | (__ 
  |_|_|___|_|  \___|\___\___|_| \_/ \___|_|(_)___|
     |_____|                                      

  Copyright 2010 Jacques Supcik, Sc.D., Dipl. Informatik-Ing. ETHZ

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License. 

 ***************************************************************************/

#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <util/delay.h>

#define TIMER_FREQ 155   // freq = 1MHz / (2 * 64 * (1 + 77) = 100Hz
                         // T = 20ms

#define LED_GREEN   PB0
#define LED_RED     PB1
#define INPUT       PB2
#define OUTPUT      PB3

#define LED_FREE    LED_GREEN
#define LED_BLOCKED LED_RED

#define DEBOUNCE0  50 // 1 sec
#define DEBOUNCE1  25 // 0.5 sec

volatile uint8_t count = 0;
volatile uint8_t state = 0;

// INT0 -> sender is visible, nothing is in between, so signal is OFF
ISR(INT0_vect) {
    if (state == 0) {
        TCNT0 = 0;
    } else if (state == 2) {
        state = 3;
    }
}

// Timer overflow -> sender is no more visible, someting is in between,
// or still in de-bounce, so signal is ON
ISR(TIMER0_COMPA_vect) {
    if (state == 0) {
        PORTB = (PORTB & ~(_BV(LED_BLOCKED) | _BV(OUTPUT))) | _BV(LED_FREE);
        state = 1;
        count = 0;
   } else if (state == 1) {
       count++;
       if (count > DEBOUNCE0) {
           state = 2;
       }
   } else if (state == 3) {
        state = 4;
        count = 0;
   } else if (state == 4) {
        count++;
        if (count > DEBOUNCE1) {
            PORTB = (PORTB & ~(_BV(LED_FREE)))
                | _BV(LED_BLOCKED)
                | _BV(OUTPUT);
            state = 0;
        }
   }
}

ISR(BADISR_vect) {
}

int main(void) {

    GIMSK |= _BV(INT0);                 // Enable external pin interrupt
    MCUCR |= _BV(ISC01);                // Enable INT0 on falling edge

    TIMSK |= _BV(OCIE0A);               // Enable Timer Interrupt on compare A
    OCR0A  = TIMER_FREQ;
    TCCR0A |= _BV(WGM01);               // Set counter 0 in CTC mode
    TCCR0B |= _BV(CS01) | _BV(CS00);    // prescale 64

    DDRB  |= _BV(LED_FREE) | _BV(LED_BLOCKED) | _BV(OUTPUT);
    PORTB = (PORTB & ~(_BV(LED_FREE))) | _BV(LED_BLOCKED) | _BV(OUTPUT)
            | _BV(PB4) | _BV(PB5);
    sei();

    for (;;)
        sleep_mode();

    return 0;
}

